package com.hcf.admin.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hcf.admin.common.constant.RedisCacheConstant;
import com.hcf.admin.common.convention.enums.UserErrorCodeEnum;
import com.hcf.admin.common.convention.exception.ClientException;
import com.hcf.admin.common.convention.result.Result;
import com.hcf.admin.common.convention.result.ResultTool;
import com.hcf.admin.dao.entity.UserDO;
import com.hcf.admin.dao.mapper.UserMapper;
import com.hcf.admin.dto.req.ShortlinkGroupSaveReqDto;
import com.hcf.admin.dto.req.UserLoginReqDto;
import com.hcf.admin.dto.req.UserRegisterReqDto;
import com.hcf.admin.dto.req.UserUpdateReqDto;
import com.hcf.admin.dto.resp.UserLoginRespDto;
import com.hcf.admin.dto.resp.UserRespDto;
import com.hcf.admin.service.GroupService;
import com.hcf.admin.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * 用户实现类
 */
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, UserDO> implements UserService  {

    @Autowired
    private RBloomFilter<String> userRegisterCachePenetrationBloomFilter;
    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private GroupService groupService;

    @Override
    public UserRespDto getUserByUsername(String username) {
        QueryWrapper<UserDO> wrapper = new QueryWrapper<>();
        wrapper.eq("username", username);
        UserDO userDO = baseMapper.selectOne(wrapper);
        if(userDO == null) throw new ClientException(UserErrorCodeEnum.USER_NULL);
        UserRespDto userRespDto = new UserRespDto();
        BeanUtils.copyProperties(userDO, userRespDto);
        return userRespDto;
    }

    @Override
    public boolean hasUsername(String username) {
//        QueryWrapper<UserDO> wrapper = new QueryWrapper<>();
//        wrapper.eq("username", username);
//        UserDO userDO = baseMapper.selectOne(wrapper);
//        return userDO == null;
        return userRegisterCachePenetrationBloomFilter.contains(username);
    }

    @Override
    @Transactional
    public Result userResigter(UserRegisterReqDto userRegisterReqDto) {
        if(hasUsername(userRegisterReqDto.getUsername())){
            throw new ClientException(UserErrorCodeEnum.USER_NAME_EXIST);
        }
        RLock lock = redissonClient.getLock(RedisCacheConstant.LOCK_USER_REGISTER_KEY + userRegisterReqDto.getUsername());
        try {
            if(lock.tryLock()){
                UserDO userDO = BeanUtil.toBean(userRegisterReqDto, UserDO.class);
                int insert = baseMapper.insert(userDO);
                if(insert <1) throw new ClientException(UserErrorCodeEnum.USER_SAVE_EROOR);
                userRegisterCachePenetrationBloomFilter.add(userDO.getUsername());
                groupService.saveGroup(userDO.getUsername(), new ShortlinkGroupSaveReqDto("默认分组"));
                return ResultTool.success();
            }else {
                throw new ClientException(UserErrorCodeEnum.USER_NAME_EXIST);
            }
        }finally {
            lock.unlock();
        }

    }


    @Override
    public Result userUpdate(UserUpdateReqDto userUpdateReqDto){
        UpdateWrapper<UserDO> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("username", userUpdateReqDto.getUsername());
        baseMapper.update(BeanUtil.toBean(userUpdateReqDto, UserDO.class), updateWrapper);
        return ResultTool.success();
    }

    @Override
    public Result userLogin(UserLoginReqDto userLoginReqDto) {

        QueryWrapper<UserDO> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username", userLoginReqDto.getUsername());
        UserDO userDO = baseMapper.selectOne(queryWrapper);

        if(userDO == null){
            throw new ClientException(UserErrorCodeEnum.USER_NULL);
        }
        System.out.println(userDO.getPassword());
        if(!userDO.getPassword().equals(userLoginReqDto.getPassword())){
            throw new ClientException(UserErrorCodeEnum.USER_PASSWORD_ERROR);
        }
        if(stringRedisTemplate.hasKey("login_" + userDO.getUsername())){
            throw new ClientException("用户已登录");
        }
        String token = UUID.randomUUID().toString();
        stringRedisTemplate.opsForHash().put("login_" + userDO.getUsername(), token, JSON.toJSONString(userDO));
        stringRedisTemplate.expire("login_" + userDO.getUsername(), 30L, TimeUnit.DAYS);

        return ResultTool.success(new UserLoginRespDto(token));

    }

    @Override
    public Boolean isLogin(String username, String token) {
        Object loginUser = stringRedisTemplate.opsForHash().get("login_" + username, token);
        return loginUser != null;
    }

    @Override
    public void logout(String username, String token) {
        if(isLogin(username, token)){
            stringRedisTemplate.delete("login_" + username);
            return;
        }
        else {
            throw new ClientException("用户token不存在或用户未登录");
        }
    }


}
